package com.powergisol.gis.service.impl;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.metadata.Sheet;
import com.powergisol.gis.Enum.ServiceTypeEnum;
import com.powergisol.gis.dao.*;
import com.powergisol.gis.dto.ExcelPileModelDTO;
import com.powergisol.gis.entity.*;
import com.powergisol.gis.listener.PileModelListener;
import com.powergisol.gis.service.SaveDataService;
import com.powergisol.gis.service.TabPiLeService;
import com.powergisol.gis.util.FileUpload;
import com.powergisol.gis.util.FileUtil;
import com.powergisol.gis.util.Result;
import com.powergisol.gis.util.ZipUtil;
import com.powergisol.gis.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author : laishihao
 * @date : 2020/10/24
 * description :
 */
@Service
public class TabPiLeServiceImpl implements TabPiLeService {

    @Value("${earth-url}")
    private String earthUrl;

    @Autowired
    private TabPileOtherMapper OtherMapper;
    @Autowired
    private TabPileReinforcementMapper reinforcementMapper;
    @Autowired
    private TabPileReinforcementDetailsMapper detailsMapper;
    @Resource
    private TabDataSettingMapper tabDataSettingMapper;

    @Autowired
    private SaveDataService saveDataService;

    @Resource
    private TabMouldMapper tabMouldMapper;

    @Resource
    private CacheManager cacheManager;

    @Autowired
    private TabPileMapper tabPileMapper;

    @Autowired
    private TabLayerMapper tabLayerMapper;

    @Autowired
    private TabTreeMapper tabTreeMapper;

    /**
     * 缓存数据检查线程池大小核心线程数
     */
    private static final int DEVICE_DATA_DISPOSE_THREAD_CORE_POOL_SIZE = 5;
    /**
     * 缓存数据检查线程池大小最大并发数
     */
    private static final int DEVICE_DATA_DISPOSE_THREAD_MAXIMUM_POOL_SIZE = 40;
    /**
     * 数据处理线程池最大待处理任务量
     */
    private static final int MAX_WAIT_TASK_COUNT = 5000;
    private static ThreadPoolExecutor excelDataDisposeThreadPool;

    static {
        excelDataDisposeThreadPool = new ThreadPoolExecutor(DEVICE_DATA_DISPOSE_THREAD_CORE_POOL_SIZE,
                DEVICE_DATA_DISPOSE_THREAD_MAXIMUM_POOL_SIZE,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(MAX_WAIT_TASK_COUNT), r -> {
            Thread thread = new Thread(r);
            thread.setDaemon(true);
            return thread;
        });
    }


    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Result excelImport(MultipartFile excelFile, TabPileVO vo, TabUserVo tabUserVo) {
        Result result = new Result();
        Map<String, Object> map = new HashMap<>();
        Integer settingId = null;
        Integer serviceId = null;

        try {
            String uuid = vo.getUuid();
            String userDir = System.getProperty("user.dir");

            //上传文件
            result = FileUpload.fileUpload(excelFile, userDir, uuid);
            userDir = (String) result.getData();


            String fileName1 = excelFile.getName();
            vo.setFileName(fileName1);
            // 获取文件名
            String fileName = excelFile.getOriginalFilename();
            // 获取文件的后缀名
            vo.setFileName(fileName.substring(0, fileName.lastIndexOf(".")));

            //发布服务
            SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMddHHmmss");
            String serviceName = vo.getFileName() + sdf1.format(new Date());
            TabServiceVo tabServiceVo = new TabServiceVo();
            tabServiceVo.setServiceUrl(earthUrl + serviceName);
            //根据用户查询用户
            tabServiceVo.setUserId(tabUserVo.getId());

            tabServiceVo.setName(serviceName);
            tabServiceVo.setReleaseTime(new Date());
            tabServiceVo.setServiceType(ServiceTypeEnum.ZEXCEL.getValue());
            tabServiceVo.setUuid(vo.getUuid());

            tabDataSettingMapper.saveService(tabServiceVo);
            tabDataSettingMapper.saveUserService(tabServiceVo.getUserId(), tabServiceVo.getId());
            serviceId = tabServiceVo.getId();
            TabDataSetting dataSetting = new TabDataSetting();
            dataSetting.setUuid(vo.getUuid());
            dataSetting.setCreateUser(tabUserVo.getName());
            dataSetting.setDataType(1);
            dataSetting.setDataUrl(userDir);
            dataSetting.setCreateTime(new Date());
            dataSetting.setServiceId(serviceId);
            TabCoordinateSystem system = new TabCoordinateSystem();
            if (1 == vo.getIsChange()) {
                system = tabMouldMapper.getCoorByName(vo.getCoorName());
                dataSetting.setCoorName(vo.getCoorName());
            }
            //保存入库
            tabDataSettingMapper.saveDataSetting(dataSetting);
            settingId = dataSetting.getId();
            //解压文件
            String zipUrl = userDir.substring(0, userDir.lastIndexOf(File.separator)) + File.separator + uuid;
            ZipUtil.unZip(userDir, zipUrl);
            List<File> listFile = FileUtil.recursionFile(zipUrl, null);
            Cache cache = cacheManager.getCache("cache-data");
            //失败数据
            StringBuffer sb = new StringBuffer();

            AtomicReference<Integer> cgNum = new AtomicReference<>(0);
            List<ExcelInFailedDataVo> listFailed = new ArrayList<>();

            ExcelPileModelDTO excelPileModelDTO = new ExcelPileModelDTO();
            List<Future<?>> taskList = new ArrayList<>();
            for (File file : listFile) {
                String excelName = file.getName();
                TabCoordinateSystem finalSystem = system;
                Future<?> task = excelDataDisposeThreadPool.submit(() -> {
                    try {
                        TabPileVO vo2 = new TabPileVO();
                        BeanUtils.copyProperties(vo, vo2);
                        PileModelListener listener = new PileModelListener(vo2, finalSystem, cacheManager,
                                excelPileModelDTO);

                        Sheet sheet = new Sheet(1, 0);
                        EasyExcelFactory.readBySax(new FileInputStream(file.getAbsolutePath()), sheet, listener);
                        if (null != cache.get(excelName + "sb")) {
                            TaskResultVo taskResultVo = cache.get(excelName + "sb", TaskResultVo.class);
                            listFailed.addAll(taskResultVo.getListFailed());
                        } else {
                            cgNum.set(cgNum.get() + 1);
                        }
                    } catch (Exception e) {
                        sb.append(excelName + ";");
                    }
                });
                taskList.add(task);
            }

            waitTaskListCompleted(taskList);
            //持久化excel模型数据
            tabPileMapper.insertSelectiveList(excelPileModelDTO.getPileList());
            OtherMapper.insertSelectiveList(excelPileModelDTO.getPileOtherList());
            detailsMapper.insertSelectiveList(excelPileModelDTO.getDetailsList());
            reinforcementMapper.insertSelectiveList(excelPileModelDTO.getReinforcementList());
//            this.saveBatch(excelPileModelDTO.getPileList());

            //返回信息
            map.put("tabDataSetting", dataSetting);
            map.put("tabService", tabServiceVo);
            System.out.println("解析结束");
            map.put("成功条数", cgNum);
            map.put("失败数据", listFailed);
            tabServiceVo.setState(1);
            tabServiceVo.setFileUrl(userDir);
            tabDataSettingMapper.updateService(tabServiceVo);


        } catch (Exception e) {
            e.printStackTrace();
            //删除已保存的数据(tab_service\tab_user_service\tab_data_setting)
            if (null != serviceId) {
                tabDataSettingMapper.delTabDataSetting(serviceId);
                tabDataSettingMapper.delTabService(serviceId);
                tabDataSettingMapper.delUserService(serviceId);
            }
            tabPileMapper.delTabPile(vo.getUuid());
            tabPileMapper.delTabPileOther(vo.getUuid());
            tabPileMapper.delTabPileReinforcement(vo.getUuid());
            tabPileMapper.deldelTabPileReinforcementDetails(vo.getUuid());

            return result.failure(500, "系统错误");
        }
        result.success(map);
        return result;
    }

    private void waitTaskListCompleted(List<Future<?>> list) throws InterruptedException {
        int finash;
        do {
            finash = 0;
            for (Future<?> future : list) {
                if (future.isDone()) {
                    finash++;
                }
            }
            Thread.sleep(100);
        } while (finash < list.size());
    }

    @Override
    public Result pileDetail(String uuid, String hcdm01) {
        Result r = new Result();
        Map<String, Object> map = new HashMap<>();
        TabPile pile = tabPileMapper.getPileDetail(uuid, hcdm01);
        map.put("pile", pile);

        List<TabPileReinforcement> pileRein = tabPileMapper.getReins(uuid, hcdm01);
        map.put("pileRein", pileRein);

        List<TabPileReinforcementDetails> pileReinDetails = tabPileMapper.getReinDetails(uuid, hcdm01);
        map.put("pileReinDetails", pileReinDetails);
        r.setData(map);
        return r;
    }

    @Override
    public Result delPileByServiceName(String serviceName) {
        Result result = new Result();
        try {
            TabServiceVo vo = tabDataSettingMapper.getByServiceName(serviceName);
            if (null == vo) {
                return result.failure(404, "数据不存在");
            }
            //删除服务、服务用户中间表
            tabDataSettingMapper.delUserService(vo.getId());
            tabDataSettingMapper.delTabService(vo.getId());

            //删除批次、桩的相关数据
            tabDataSettingMapper.delTabDataSetting(vo.getId());
            tabPileMapper.delTabPile(vo.getUuid());
            tabPileMapper.delTabPileOther(vo.getUuid());
            tabPileMapper.delTabPileReinforcement(vo.getUuid());
            tabPileMapper.deldelTabPileReinforcementDetails(vo.getUuid());

            //删除layer、场景layer中间表、树中对应的layer
            List<TabLayer> tabLayers = tabLayerMapper.getByServiceId(vo.getId());
            for (TabLayer layer : tabLayers) {
                tabLayerMapper.deleteLayerById(layer.getId());
                tabLayerMapper.deleteSceneLayerById(layer.getId());
                tabTreeMapper.delTreeByLayerId(layer.getId());
            }
        } catch (Exception e) {
            result.failure(500, "删除异常");
        }
        return result;
    }

//
//    public static void main(String[] args) {
//        //第三方接口请求的地址
//        String Url = "http://api.data.cma.cn:8090/api";
//
//        //调用接口需要的参数
//        Map<String, String> map = new HashMap<>();
//        map.put("userId","604305754835603OL");
//        map.put("pwd","1675OX9");
//        map.put("dataFormat","json");
//        map.put("interfaceId","getSurfEleByTimeRangeAndStaID");
//        map.put("dataCode","SURF_CHN_MUL_HOR");
//        map.put("timeRange","[20201101142227,20201103152227]");
//        map.put("staIDs","59493");
//        map.put("elements","Station_Id_C,Year,Mon,Day,Hour,PRE_1h,TEM,WEP_Now,TEM_Max,TEM_Min");
//
//        HttpClientUtil1 http = new HttpClientUtil1();
//        String s = http.doGet(Url, map);
//        System.out.println(s);
//
//        JSONObject jsonObject = JSONObject.parseObject(s);
//        Object accessToken = jsonObject.get("DS");
//        String data = accessToken.toString();
//        System.out.println(data);
//    }
}
